由来:如今,气象与人们的生活密不可分,尤其对于植物爱好者来说,准确的气象预测能帮助他们更好的管理控制植物的生活环境,可市面上大多的天气预报皆是一个大范围的概况,如一个城市为单位,这些气象值与其中的一个小区域范围的气象值往往存在不少的偏差,所以我想设计一款监控小区域范围内天气状况的app,能帮助植物爱好者更好的了解植物所处范围内的气象状况。
设计与思路;首先,软件的功能拟定了五项最为普遍的测量项,分别是温度,湿度,气压,紫外线和PM2.5。并通过蓝牙将手机与单片机相连,达到数据的传输与反馈,同时,除了单片机测量的区域性气象,软件上还能通过网络,了解到大范围的天气状况,我还想到在天气闷热的情况下,能否通过手机控制来达到降温的作用,于是我又在单片机上添加来协助完成散热的功能。
这款app通过蓝牙控制传输和接收信息,气象站上主要有温度,湿度传感器,气压传感器,紫外线传感器和PM2.5传感器,当单片机将这五项数据采集并转化后,通过蓝牙将数据发送至手机,再通过对所发送的信息进行提取,方便使用者能直观的在手机上看到每项数据值,并做出对植物环境的调整与防范,不仅是小区域范围的天气监测,app中还有可连接网络查询大区域范围的功能,另外,气象站上还有一个小马达,通过手机上的open和stop键控制,在天气过于闷热的情况下,对植物进行一定的散热。
关键词,气象监测,小区域,手机软件
本项目主要创新点:
通过蓝牙湿手机程序和单片机程序通讯,可监测小范围精准的气象情况,
手机端链接网络,可查询大范围气象情况
单片机端上连接小马达作为风扇,通过手机端控制为植物降温。
目 录
第一章 序言...................................................................................................3
1.1选题由来.....................................................................................................................3
1.2研究内容.....................................................................................................................3
第二章 技术方案的设计与实现.......................................................................4
2.1技术方案的选定..........................................................................................................4
2.2装置功能总介绍..........................................................................................................5
2.3运行原理及其逻辑图..................................................................................................5
2.4装置核心结构介绍及开发..........................................................................................7
第三章 结论与展望...............................................................................................13
感谢......................................................................................................................14
参考文献...............................................................................................................14
如今,气象与人们的生活密不可分,尤其对于植物爱好者来说,准确的气象预测能帮助他们更好的管理控制植物的生活环境。
通过调查我发现
1.市面上大多的天气预报皆是一个大范围的概况,如一个城市为单位。
2.大多天气预报显示的数据大多为一个地区温湿度,气压等的平均值这些气象值与其中的一个小区域范围的真实气象值往往存在不少的偏差。
所以我想设计一款监控小区域范围内天气状况的app,能帮助植物爱好者更好的了解植物所处范围内的气象状况
我开发一款可以通过手机进行监控并控制降温的智能气象站。我开发的智能气象站的设计思想是:通过单片机连接传感器获得空气中温湿度,气压,紫外线,以及PM2.5的数据,并将数据实时传给手机端;手机端接受到数据后,结合预设的设置对数据进行分析,提取。当温度过高的情况下,通过手机给单片机发送指令,单片机通过手机发送回的指令来控制风扇的开启和关闭。
我设计并开发的智能气象站目的是针对现有市面气象报告的缺点,提出一种小范围气象测量的装置,具有结构合理、使用简便、测量精准等优点。第二章 技术方案的设计与实现
2.1.1具体方案
我开发的智能气象站的设计思想是:通过单片机连接传感器获得空气中温湿度,气压,紫外线,以及PM2.5的数据,并将数据实时传给手机端;手机端接受到数据后,结合预设的设置对数据进行分析,提取。当温度过高的情况下,通过手机给单片机发送指令,单片机通过手机发送回的指令来控制风扇的开启和关闭。
整个智能气象站主要由两部分组成,第一部分,手机端控制程序的开发。该程序主要是实现对空气中温湿度,气压,紫外线,以及PM2.5的数据的监控,同时用户可以通过手机端进行控制风扇开启达到降温目的的设置。在手机端还设计了链接网络查看大范围气象的功能。第二部分,单片机端程序开发和气象站的组建。包括单片机,温度,湿度传感器,气压传感器,紫外线传感器和PM2.5传感器。功能实现主要点:单片机控制器连接四项传感器,并控制连接风扇。
结合方案单片机控制部分和浇水的机械部分材料的选定如下,单片机开发板选择Mega 2560。Arduino Mega2560特点是采用USB接口的核心电路板,具有54路数字输入输出,适合需要大量IO接口的设计。处理器核心是ATmega2560, 同时具有54路数字输入/输出口(其中16路可作为PWM输出),16路模拟输入,4路UART接口,一个16MHz晶体振荡器,一个USB口,一个电源 插座,一个ICSP header和一个复位按钮。Arduino Mega2560也能兼容为Arduino UNO设计的扩展板。,空气温湿度传感器选择DHT11,气压传感器选择BMP085,PM2.5传感器选择SDS018-V2-012,马达选择28BYJ-48,蓝牙模块选择HC-06。 手机我们选择带蓝牙功能的安卓手机即可。
2.1.2开发流程
(1)调查如今气象普遍测量范围
(2)查阅相关书籍解决技术问题
(3)编写程序
(4)调试完善
2.1.3开发环境
手机端程序开发工具为 App Inventor 2版本。单片机程序开发软件为Arduino1.6.11 版本。
我开发的系统包括有以下一些主要功能
(1)通过开发手机程序和单片机程序结合通讯,实现远端监控。时刻检测到当前土壤湿度和空气温湿度。
(2)能够通过手机端程序对风扇进行控制启动,达到降温的目的.
(3)手机端程序链接网络,获取大范围天气预报
在设计思想的指导下,基于选定的设计方案和功能我的整个装置的逻辑图应如下图一所示:
图一
基于安卓系统的智能气象站的手机端的逻辑图如下图二所示:
图二
基于安卓系统的智能气象站的单片机控制端的逻辑图如下图三所示
基于安卓系统的智能气象站的单片机端2控制的逻辑图如下图四所示
图四
(1)单片机和手机互相通讯问题
智能气象站系统包括手机端和单片机端,为了使数据信息传递,在整个系统开发中,首先要解决的问题这两个设备之间的通讯问题。从各方面考虑,我最终选定蓝牙技术作为本项目中的通讯方式。
第一、选定并正确连接蓝牙模块,蓝牙模块为HC-06 ,将蓝牙模块的RXD,TXD(数据接受端)分别连接在Mega 2560单片机的TX3,RX3数据发送端。见下图五
第二、确定通讯约定和单片机端编写通讯程序。通讯约定为八为一组,具体分操作模式,命令,数据三类,如下所示:
由1) Command:
CX : C -- tag for Command
X -- 1 : request for the temperature and humidity value
2 : request for the pressure value
3 : request for the PM2.5 and UV value
3) Data:
D1XYZABC: D -- tag for Data
XYZ -- XY : integer value of temperature
Z : fractional value of temperature
ABC -- AB : integer value of humidity
C : fractional value of humidity
D2UVWXYZ: D -- tag for Data
UVWXYZ -- Air pressure value
D3HIJKUV: D -- tag for Data
HIJK -- value of PM2.5
U -- UV level
上述可知如果手机端蓝牙接收到“D1191189”表示当前空气温度为19.1度,湿度为18.9%,。如果手机端蓝牙接收到“D2101822”表示气压为101822pa。如果手机端蓝牙接收到“D3115025”,表示PM2.5为115.0μg/m3,紫外线为25。单片机往串口3发送信息时,因为HC-06蓝牙模块接在Mega 2560单片机的RX3和TX3,所以蓝牙模块就能收到信息。
第三、手机端的蓝牙作为蓝牙客户端。接受从单片机端的蓝牙模块发送过来的信息。在通讯时,手机端蓝牙首先要与单片机蓝牙联机,手机端编写联机代码如下图五:
图五
手机端发送的代码如下图六:
手机端接受信息的代码如下图七:
图七
(2)单片机对风扇的控制
当温度过高的情况下,通过手机给单片机发送指令,单片机通过手机发送回的指令来控制风扇的开启和关闭。如下图八所示:
解决了关键性的技术后,我设计开发了基于安卓系统的智能气象站,开发出的实物图如下图1:
图1
我的整个系统经过多次测试效果良好,小范围的数据都很准确,所有的功能都达到了我的预期要求,可以监控小区域范围内天气状况,帮助植物爱好者更好的了解植物所处范围内的气象状况。我设计的基于安卓系统的智能气象站将手机程序和单片机程序实现通讯。整个温度,湿度传感器,气压传感器,紫外线传感器和PM2.5传感器测得数据并传给Mega 2560单片机,再由单片机的输出到蓝牙模块。蓝牙再将信息发给手机,手机接收到信息显示出来,作为参考值。智能气象站是通过单片机将测量值发送给手机,手机端对数据进行分析和提取.同时,通过手机上的open和stop键控制单片机端,在天气过于闷热的情况下,对植物进行一定的散热。
通过这次项目的实践过程,我不但学会了一些单片机编程的基础知识,也丰富了我对编程方面的知识与认知。严密的编程锻炼了我的逻辑思维,项目的组装时的种种困难也锻炼了我坚持下去的意志,培养了坚持不懈,刻苦钻研问题的精神。这些收获是我在完成项目的过程中最为可贵的的。
对于我的智能气象站,进一步设想和改进:可增加警告提示,比如当某一项值超过正常范围,显示提示,使植物爱好者能更直观的发现并作出防范
本次项目是我在老师的细心辅导下完成的。从课题一开始的选择方向与发展方向,到实体物体的组装与软件的开发,再到最后项目的完成,老师都在我的身边细心耐心的辅导我,鼓励我。在课题的整个研究工作期间,每当我遇见技术上的问题时,他总是耐心的为我讲解,使我不断的坚持努力下来,并对我的项目提出了不少建议,使我不断改进完善自我,使我的项目更加科学严密。在此谨向老师致以衷心的感谢和深深的敬意!谢谢老师。
[1] 郑剑春, 张少华 . App Inventor 2与机器人程序设计[M]. 清华大学出版社. 第1版 (2016年8月1日).
[2] 王寅峰 (编者). App Inventor 2 中文版开发实战:Android智能应用开发前传[M]. 电子工业出版社; 第1版 (2015年8月1日).
[3] 沃尔贝 (David Wolbe) , 埃布尔森 (Hal Abelson) , 斯珀特斯 (Ellen Spertus) , 卢尼 (Liz Looney) , 金从军 (译者). 写给大家看的安卓应用开发书:App Inventor 2快速入门与实战[M]. 人民邮电出版社.第1版 (2016年6月1日).
[4]吴亚峰 杜化美 苏亚光(作者),《Android编程典型实例与项目开发》,电子工业出版社
[5]佘志龙、郑名杰(作者)等,《Android SDK开发范例大全 第2版》,人民邮电出版社
[6]高彩丽 袁海(作者)等,《Android SDK应用开发范例精解》,清华大学出版社
清华大学出版社 2012年11月
[9] [美] Michael Margolis .臧海波 译.《学Arduino玩转机器人制作》[M].人民邮电出版社.2014-04-30
[10] [澳]John BOXALL著 翁恺 译.《动手玩转Arduino》[M].北京人民邮电出版社.2014年1月204-210
[11] [美]Gordon McComb著,唐乐译.《Arduino机器人制作指南》[M].科学出版社.2014年1月
[12] Simon Monk 著,唐乐 译.《Arduino+Android互动智作》[M].科学出版社.2013-1
附录
*/
/*******************Port Interface**************
Arduino Mega DHT-22
D5 DAT
+5V VCC
GND GND
/*******************Port Interface**************
Arduino Mega BlueTooth HC06
TX3 RX
RX3 TX
+5V VCC
GND GND
/*******************Port Interface**************
Arduino Mega I2C LCD 1602
GND GND
+5V VCC
SCL SCL
SDA SDA
/*******************Port Interface**************
Arduino Mega BMP085
GND GND
+5V VCC
SCL SCL
SDA SDA
/*******************Port Interface**************
Arduino Mega DS3231
GND GND
+5V VCC
SCL SCL
SDA SDA
/*******************Port Interface**************
Arduino Mega PM2.5 SDS018
TX2 RX
RX2 TX
+5V VCC
GND GND
/*******************Port Interface**************
Arduino Mega UV Sensor
A0 DAT
+5V VCC
GND GND
Communication protocal:
1) Command:
CX : C -- tag for Command
X -- 1 : request for the temperature and humidity value
2 : request for the pressure value
3 : request for the PM2.5 and UV value
3) Data:
D1XYZABC: D -- tag for Data
XYZ -- XY : integer value of temperature
Z : fractional value of temperature
ABC -- AB : integer value of humidity
C : fractional value of humidity
D2UVWXYZ: D -- tag for Data
UVWXYZ -- Air pressure value
D3HIJKUV: D -- tag for Data
HIJK -- value of PM2.5
U -- UV level
*/
#include 
#include "DS3231.h"
#include 
#include 
#include 
LiquidCrystal_I2C lcd(0x20,16,2); // set the LCD address to 0x20 for a 16 chars and 2 line display
dht DHT; //Create the DHT22 object
DS3231 RTC; //Create the R8025 object
BMP085 dps = BMP085(); // Digital Pressure Sensor
#define DHT22_PIN 5
char weekDay[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
byte integerTem = 0;
byte fractionalTem = 0;
byte integerHum = 0;
byte fractionalHum = 0;
long pressure = 0;
long tmp_pressure = 0;
byte uvLevel = 0;
byte SDS018_buf[10] = {0};
byte indexPM25 = 0;
uint8_t CRC_Check = 0;
uint16_t PM25 = 0;
uint16_t PM10 = 0;
uint16_t tmpPM25 = 0;
uint16_t tmpPM10 = 0;
byte index = 0;
byte Rx_buf[2] = {'0','0'};
byte DHT_buf[8] = {'D','1','0','0','0','0','0','0'};
byte Air_buf[8] = {'D','2','0','0','0','0','0','0'};
byte PM25_buf[8] = {'D','3','0','0','0','0','0','0'};
void setup ()
{
pinMode(A0,INPUT);
Serial.begin(9600);
Serial2.begin(9600);
Serial3.begin(9600);
lcd.init(); // initialize the lcd
Wire.begin();
RTC.begin(); // initialize the DS3231
dps.init(MODE_ULTRA_HIGHRES, 1000, true); // 10 meters, true = using meter units
lcd.backlight();
// lcd.noBacklight();
lcd.setCursor(0,0);
lcd.print("0000/00/00 00.0C");
lcd.setCursor(0,1);
lcd.print("00.0% 000000Pa");
}
void loop ()
{
ShowDate();
showHumidity_Temperature();
showPressure();
showUVLevel();
for(int i=0;i<8;i++)
Serial.print(char(DHT_buf[i]));
Serial.println();
delay(1000);
}
void ShowDate(void){
DateTime now = RTC.now(); //get the current date-time
lcd.setCursor(0,0);
lcd.print(now.year());
if(now.month()>9)
lcd.setCursor(5,0);
else
lcd.setCursor(6,0);
lcd.print(now.month());
if(now.date()>9)
lcd.setCursor(8,0);
else
lcd.setCursor(9,0);
lcd.print(now.date());
Serial.print(now.year());
Serial.print('/');
Serial.print(now.month());
Serial.print('/');
Serial.print(now.date(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.print(' ');
Serial.print(weekDay[now.dayOfWeek()-1]);
Serial.println();
}
void showHumidity_Temperature(){
Serial.print("DHT22, \t");
int chk = DHT.read22(DHT22_PIN);
switch (chk)
{
case DHTLIB_OK:
Serial.print("OK,\t");
break;
case DHTLIB_ERROR_CHECKSUM:
Serial.print("Checksum error,\t");
break;
case DHTLIB_ERROR_TIMEOUT:
Serial.print("Time out error,\t");
break;
default:
Serial.print("Unknown error,\t");
break;
}
// DISPLAY DATA
Serial.print(DHT.humidity, 1);
Serial.print(",\t");
Serial.print(DHT.temperature, 1);
Serial.println();
integerTem = int(DHT.temperature)/1;
fractionalTem = int(DHT.temperature*10)%10;
DHT_buf[2] = IntToByte(integerTem/10);
DHT_buf[3] = IntToByte(integerTem%10);
DHT_buf[4] = IntToByte(fractionalTem);
lcd.setCursor(11,0);
lcd.print(integerTem);
lcd.setCursor(14,0);
lcd.print(fractionalTem);
integerHum = int(DHT.humidity)/1;
fractionalHum = int(DHT.humidity*10)%10;
DHT_buf[5] = IntToByte(integerHum/10);
DHT_buf[6] = IntToByte(integerHum%10);
DHT_buf[7] = IntToByte(fractionalHum);
lcd.setCursor(0,1);
lcd.print(integerHum);
lcd.setCursor(3,1);
lcd.print(fractionalHum);
}
void showPressure(void) {
dps.getPressure(&pressure);
Serial.print("Pressure(Pa):");
Serial.println(pressure);
lcd.setCursor(8,1);
lcd.print(pressure);
tmp_pressure = pressure;
Air_buf[2] = IntToByte(tmp_pressure/100000);
tmp_pressure = tmp_pressure%100000;
Air_buf[3] = IntToByte(tmp_pressure/10000);
tmp_pressure = tmp_pressure%10000;
Air_buf[4] = IntToByte(tmp_pressure/1000);
tmp_pressure = tmp_pressure%1000;
Air_buf[5] = IntToByte(tmp_pressure/100);
tmp_pressure = tmp_pressure%100;
Air_buf[6] = IntToByte(tmp_pressure/10);
tmp_pressure = tmp_pressure%10;
Air_buf[7] = IntToByte(tmp_pressure);
}
void showUVLevel(void){
byte uv_value = 0;
byte ref_level = 64;
uv_value = analogRead(A0);
Serial.println(uv_value);
uvLevel = int(uv_value/ref_level);
PM25_buf[6] = IntToByte(uvLevel/10);
PM25_buf[7] = IntToByte(uvLevel%10);
}
void serialEvent2(void){
while (Serial2.available()) {
SDS018_buf[indexPM25] = Serial2.read(); // get the new byte:
if(SDS018_buf[0] == 0xAA) indexPM25 = indexPM25+1;
else indexPM25 = 0;
if(indexPM25 > 9){
indexPM25 = 0;
CRC_Check = 0;
if(SDS018_buf[1] == 0xC0)
// for(int i=0;i<10;i++) Serial.println(SDS018_buf[i]);
for(int i=2;i<8;i++) CRC_Check += SDS018_buf[i];
if(CRC_Check == SDS018_buf[8]) {
Serial.println("CRC passed!");
PM25 = (uint16_t)SDS018_buf[2] | (uint16_t)(SDS018_buf[3]<<8);
PM10 = (uint16_t)SDS018_buf[4] | (uint16_t)(SDS018_buf[5]<<8);
Serial.println(PM25);
Serial.println(PM10);
tmpPM25 = PM25;
PM25_buf[2] = IntToByte(tmpPM25/1000);
tmpPM25 = tmpPM25%1000;
PM25_buf[3] = IntToByte(tmpPM25/100);
tmpPM25 = tmpPM25%100;
PM25_buf[4] = IntToByte(tmpPM25/10);
tmpPM25 = tmpPM25%10;
PM25_buf[5] = IntToByte(tmpPM25);
}
}
}
}
void serialEvent3(){
while (Serial3.available()) {
Rx_buf[index] = Serial3.read(); // get the new byte:
if(Rx_buf[0] == 'C') index = index+1;
else index = 0;
if(index > 0){
index = 0;
if(Rx_buf[1] == '1')
Serial3.write(DHT_buf,8);
if(Rx_buf[1] == '2')
Serial3.write(Air_buf,8);
if(Rx_buf[1] == '3')
Serial3.write(PM25_buf,8);
}
}
//Serial2.write(DHT_buf,9);
}
byte IntToByte(unsigned int var){
byte value;
switch(var){
case 0:
value = '0'; break;
case 1:
value = '1'; break;
case 2:
value = '2'; break;
case 3:
value = '3'; break;
case 4:
value = '4'; break;
case 5:
value = '5'; break;
case 6:
value = '6'; break;
case 7:
value = '7'; break;
case 8:
value = '8'; break;
case 9:
value = '9'; break;
default:
value = '0'; break;
}
return value;
}